require "#{ENV["TM_SUPPORT_PATH"]}/lib/escape"
require "#{ENV["TM_SUPPORT_PATH"]}/lib/web_preview"

require 'open3'
require 'cgi'
require 'fcntl'
require "tempfile"

$S2PHP5MATE_VERSION = "$Revision: 1 $"

class UserScript
  def initialize
    @tmp     = create_tmp(STDIN.read)
    @content = @tmp.read
    @path    = @tmp.path
    
    @arg0 = $1       if @content =~ /\A#!([^ \n]+\/php\b)/
    @args = $1.split if @content =~ /\A#!.*?\bphp[ \t]+(.*)$/
    
    @display_name = 
      if ENV.has_key? 'TM_FILEPATH'
        File.basename(ENV['TM_FILEPATH'])
      else
        'untitled'
      end
  end

  def php_version_string
    res = %x{ #{php} -r 'print phpversion();' }
  end

  def run
    rd, wr = IO.pipe
    rd.fcntl(Fcntl::F_SETFD, 1)
    ENV['TM_ERROR_FD'] = wr.to_i.to_s
    args = add_test_path( *[ php,
                             Array(@args), @path, ARGV.to_a ].flatten )
    stdin, stdout, stderr = Open3.popen3(*args)
    Thread.new { stdin.write @content; stdin.close } unless ENV.has_key? 'TM_FILEPATH'
    wr.close

    [ stdout, stderr, rd ]
  end

  def test_script?
    @content =~ /PHPUnit2*_Framework_TestCase/
  end

  attr_reader :display_name, :path
  
  private
  def php
    @arg0 || ENV['TM_PHP'] || 'php'
  end

  def phpunit
    ENV['TM_PHPUNIT'] || 'phpunit'
  end
  
  def add_test_path(*args)
    if test_script?
      test_class_matched = @content.match(/class (.+Test) extends PHPUnit2*_Framework_TestCase/)
      if test_class_matched
        test_class_name = test_class_matched[1].strip
        args[0] = phpunit
        args.insert 1, test_class_name
      end
      if s2base? && ENV['TM_S2BASE_ROOT']
        add_s2base_env_file
      end
    end
    args
  end
  
  def s2base?
    @content =~ /S2BASE_PHP5_ROOT/
  end
  
  def add_s2base_env_file
      env_inc = ENV['TM_S2BASE_ROOT'] + '/config/environment.inc.php'
      content = @content.sub(/(\<\?php)/i, "<?php\ninclude_once('#{env_inc}');\n")
      @tmp.close(true)
      @tmp = create_tmp content
      @content = @tmp.read
      @path    = @tmp.path
  end
  
  def create_tmp(content)
    tmp = Tempfile.new("s2php5mate")
    tmp.puts content
    tmp.close
    tmp.open
    tmp
  end
  
end

error = ""
STDOUT.sync = true

script = UserScript.new

puts html_head(:window_title => "#{script.display_name} — S2PHP5Mate", :page_title => 'S2PHP5Mate', :sub_title => 'S2PHP5')
puts <<-HTML
	<div class="rubymate">
		
		<div><!-- first box containing version info and script output -->
			<pre><strong>S2PHP5Mate r#{$S2PHP5MATE_VERSION[/\d+/]} running PHP5 v#{script.php_version_string}</strong>
<strong>>>> #{script.display_name}</strong>

<div style="white-space: normal; -khtml-nbsp-mode: space; -khtml-line-break: after-white-space;"> <!-- Script output -->
HTML

stdout, stderr, stack_dump = script.run
descriptors = [ stdout, stderr, stack_dump ]

descriptors.each { |fd| fd.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK) }
until descriptors.empty?
  select(descriptors).shift.each do |io|
    str = io.read
    if str.to_s.empty? then
      descriptors.delete io
      io.close
    elsif io == stdout then
      if script.test_script? and str =~ /\A[.EF]+\Z/
        print htmlize(str).gsub(/[EF]+/, "<span style=\"color: red\">\\&</span>") +
              "<br style=\"display: none\"/>"
      else
        if script.test_script?
          print( str.map do |line|
            if line =~ /(FAILURES.+)/
"<span style=\"color: red\">#{$1}</span><br/>"
            elsif line =~ /(OK\s\(\d+\stest.+)/
"<span style=\"color: green\">#{$1}</span><br/>"
            else
              htmlize(line)
            end
          end.join )
	      else
	        print htmlize(str)
        end
      end
    elsif io == stderr then
      print "<span style='color: red'>#{htmlize str}</span>"
    elsif io == stack_dump then
      error << str
    end
  end
end

puts '</div></pre></div>'
puts error
puts '<div id="exception_report" class="framed">Program exited.</div>'
puts '</div>'
puts '</body></html>'